/*
 * @Description: Delay queue
 * @Version: 1.0
 * @Autor: kane
 * @Date: 2021-02-15 22:26:59
 */ 

#include "delayQueue.h"

/**
 * @brief  Queue timing base.
 */
uint64_t g_delayQueueRunTime = 0;

/**
 * @brief  Time base increment handle.
 * @note   You should put it in the systick handle().
 * @retval None.
 */
void runTimeHandle(void)
{
	g_delayQueueRunTime++;
}

/**
 * @brief  Gets the current elapsed time.
 * @note   In general, don't make changes.
 * @retval timing base (uint64_t).
 */
uint64_t getRunTime(void)
{
	return g_delayQueueRunTime;
}

/**
 * @brief  Queue enqueuing function.
 * @note   
 * @param  **head_t: Handle to the queue.
 * @param  cmd: event type.
 * @param  value: event value.
 * @param  delayTime: Remaining time to send.
 * @retval None
 */
void insertNode(struct delayQueueNode_T **head_t, int32_t cmd, int32_t value, uint64_t delayTime)
{
	struct delayQueueNode_T *previous_t;
	struct delayQueueNode_T *current_t;
	struct delayQueueNode_T *newNode_t;

	current_t = *head_t;
	previous_t = NULL;

    //按照剩余的发送时间排序，并找到正确的位置.
    //Sort by remaining send time, and Find the right place.
	while (current_t != NULL && current_t->m_offsetTime <= delayTime + getRunTime())
	{
		previous_t = current_t;		//previous_t记录current_t上一个节点的位置.
		current_t = current_t->next;
	}

    //检查内存分配情况，你可以修改这个函数.
    //Memory allocation is successfully determined, you can customize it.
	newNode_t = (struct delayQueueNode_T *)malloc(sizeof(struct delayQueueNode_T));
	if (newNode_t == NULL)
	{
		printf("内存分配失败!");
		exit(1);
	}

	newNode_t->m_cmd = cmd;
	newNode_t->m_value = value;
	newNode_t->next = current_t;
	newNode_t->m_offsetTime = delayTime + getRunTime();

    //将新的数据插入到队列中.
    //New data is inserted into the queue.
	if (previous_t == NULL)
	{
		*head_t = newNode_t;
	}
	else
	{
		previous_t->next = newNode_t;
	}
}

/**
 * @brief  debug
 * @param  *head_t: Handle to the queue.
 * @retval None
 */
void print32_tNode(struct delayQueueNode_T *head_t)
{
	struct delayQueueNode_T *current_t;
	current_t = head_t;
	while (current_t != NULL)
	{
		printf("%d ", current_t->m_value);
		current_t = current_t->next;
	}
	printf("\n");
}

/**
 * @brief  Take an item out of the queue.
 * @note   It can only be taken out if the remaining time is 0.
 * @param  **head_t: Handle to the queue.
 * @retval None
 */
void deleteNode(struct delayQueueNode_T **head_t)
{
	struct delayQueueNode_T *previous_t;
	struct delayQueueNode_T *current_t;

	current_t = *head_t;
	previous_t = NULL;

    //取出最先放入的数据，(数据必须延时发送时间到了).
    //Fetch the first data put in (data must be delayed to the end of the sending time).
	while (current_t != NULL && current_t->m_offsetTime >= getRunTime())
	{
		previous_t = current_t;
		current_t = current_t->next;
	}

    //队列指针后移.
    //The queue pointer is moved back.
	if (current_t == NULL)
	{
		return;
	}
	else
	{
		*head_t = current_t->next;
		free(current_t);
	}
}

/**
 * @brief  demo
 * @note   
 * @retval 
 */
int32_t main(void)
{
	struct delayQueueNode_T *head_t = NULL;

	insertNode(&head_t, 1,20,50);
	insertNode(&head_t, 1, 50, 350);
	insertNode(&head_t, 1, 60, 450);
	insertNode(&head_t, 1, 40, 250);
	insertNode(&head_t, 1, 70, 550);
	insertNode(&head_t,  1, 30, 150);
	insertNode(&head_t, 1, 10,20);
	print32_tNode(head_t);

	for (int32_t i = 0; i < 1; ++i)
	{
		runTimeHandle();
		deleteNode(&head_t);
	}
	
	print32_tNode(head_t);

	while (1)
		;

	return 0;
}